home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
grab.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
9KB
|
360 lines
/* +-------------------------------------------------------------------+ */
/* | Copyright 1993, David Koblas (koblas@netcom.com) | */
/* | | */
/* | Permission to use, copy, modify, and to distribute this software | */
/* | and its documentation for any purpose is hereby granted without | */
/* | fee, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. There is no | */
/* | representations about the suitability of this software for | */
/* | any purpose. this software is provided "as is" without express | */
/* | or implied warranty. | */
/* | | */
/* +-------------------------------------------------------------------+ */
#include <X11/Intrinsic.h>
#include <X11/cursorfont.h>
#include "image.h"
#define GRAB_FAST
/*
** Convienence function. For doing server pointer grabs
**
*/
#define GRAB_INTERVAL 30
typedef struct {
XtAppContext app;
Display *dpy;
GC gc;
Window root;
Boolean drawn;
int x, y, ox, oy, width, height;
XtIntervalId id;
} GrabInfo;
static void grabHilite(XtPointer infoArg, XtIntervalId *id)
{
GrabInfo *info = (GrabInfo*)infoArg;
if (info->drawn) {
if (info->ox == info->x && info->oy == info->y)
goto end;
XDrawRectangle(info->dpy, info->root, info->gc,
info->ox - info->width / 2,
info->oy - info->height / 2,
info->width, info->height);
}
info->drawn = True;
XDrawRectangle(info->dpy, info->root, info->gc,
info->x - info->width / 2,
info->y - info->height / 2,
info->width, info->height);
info->ox = info->x;
info->oy = info->y;
end:
info->id = XtAppAddTimeOut(info->app, GRAB_INTERVAL,
grabHilite, (XtPointer)info);
}
static void xyToWindowCmap(Display *dpy, int x, int y, Window base,
int *nx, int *ny, Window *window, Colormap *cmap)
{
Window twin;
Colormap tmap;
Window child, sub;
XWindowAttributes attr;
twin = base;
tmap = None;
sub = base;
*nx = x;
*ny = y;
while (sub != None) {
x = *nx;
y = *ny;
child = sub;
XTranslateCoordinates(dpy, base, child, x, y, nx, ny, &sub);
base = child;
XGetWindowAttributes(dpy, child, &attr);
if (attr.class == InputOutput && attr.colormap != None) {
tmap = attr.colormap;
twin = child;
}
}
if (tmap == None)
*cmap = DefaultColormap(dpy, DefaultScreen(dpy));
else
*cmap = tmap;
*window = twin;
}
static void doGrab(Widget w, int width, int height, int *x, int *y)
{
Display *dpy = XtDisplay(w);
XtAppContext app = XtWidgetToApplicationContext(w);
Window root = DefaultRootWindow(dpy);
XEvent event;
Cursor cursor = XCreateFontCursor(dpy, XC_crosshair);
int count = 0;
GrabInfo *info = NULL;
if (width != 0 && height != 0) {
XGCValues gcv;
info = XtNew(GrabInfo);
gcv.function = GXxor;
gcv.foreground = 1;
gcv.subwindow_mode = IncludeInferiors;
info->root = root;
info->app = app;
info->x = 0;
info->y = 0;
info->drawn = False;
info->dpy = dpy;
info->gc = XCreateGC(dpy, root, GCSubwindowMode|GCForeground|GCFunction, &gcv);
info->width = width;
info->height = height;
info->id = XtAppAddTimeOut(app, GRAB_INTERVAL,
grabHilite, (XtPointer)info);
}
if (XGrabPointer(dpy, root, False,
info == NULL ? ButtonPressMask|ButtonReleaseMask
: ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeSync, GrabModeAsync,
root, cursor, CurrentTime)) {
return;
}
do {
XAllowEvents(dpy, SyncPointer, CurrentTime);
XtAppNextEvent(app, &event);
if (event.type == ButtonPress)
count++;
else if (event.type == ButtonRelease) {
if (count == 1)
break;
else
count--;
} else if (event.type == MotionNotify) {
info->x = event.xmotion.x;
info->y = event.xmotion.y;
} else
XtDispatchEvent(&event);
} while (True);
XUngrabPointer(dpy, CurrentTime);
if (info != NULL) {
if (info->drawn)
XDrawRectangle(info->dpy, info->root, info->gc,
info->ox - info->width / 2,
info->oy - info->height / 2,
info->width, info->height);
XtRemoveTimeOut(info->id);
XFreeGC(XtDisplay(w), info->gc);
XtFree((XtPointer)info);
}
*x = event.xbutton.x;
*y = event.xbutton.y;
}
void *DoGrabImage(Widget w, int width, int height)
{
Screen *screen = XtScreen(w);
Display *dpy = XtDisplay(w);
Window root = RootWindowOfScreen(screen);
Colormap dmap = DefaultColormapOfScreen(screen);
int x, y, xi, yi, count, nx, ny, i, tx, ty;
int fx, fy;
Colormap cmap, lastCmap;
Window window, lastWindow;
unsigned char *ip;
Image *image;
XColor *xcol;
XImage *xim;
doGrab(w, width, height, &x, &y);
x -= width / 2;
y -= height / 2;
if (x < 0) {
width += x;
x = 0;
}
if (y < 0) {
height += y;
y = 0;
}
if (x + width > WidthOfScreen(screen))
width = WidthOfScreen(screen) - x;
if (y + height > HeightOfScreen(screen))
height = HeightOfScreen(screen) - x;
if (width == 0 || height == 0)
return NULL;
image = ImageNew(width, height);
ip = image->data;
xcol = (XColor *)XtCalloc(width, sizeof(XColor));
#ifdef GRAB_FAST
/*
** Fast grabs, just use the colormap at the 0,0 position
** gotcha is that the XImage is from the root window
** thus, with it's depth.
*/
xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, &cmap);
xyToWindowCmap(dpy, x + width, y + height, root, &tx, &ty, &lastWindow, &lastCmap);
/*
** XXX Improvment:
** instead of window == lastWindow
** we could check for common parent, and use that.
*/
if (window == lastWindow)
xim = XGetImage(dpy, window, nx, ny, width, height, AllPlanes, ZPixmap);
else
xim = XGetImage(dpy, root, x, y, width, height, AllPlanes, ZPixmap);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
xcol[x].pixel = XGetPixel(xim, x, y);
xcol[x].flags = DoRed|DoGreen|DoBlue;
}
XQueryColors(XtDisplay(w), cmap, xcol, width);
for (x = 0; x < width; x++) {
*ip++ = (xcol[x].red >> 8) & 0xff;
*ip++ = (xcol[x].green >> 8) & 0xff;
*ip++ = (xcol[x].blue >> 8) & 0xff;
}
}
#else
/*
** Slow grabs, get the correct color and colormap though a lot of
** server calls.
*/
StateSetBusyWatch(True);
for (yi = 0; yi < height; yi++) {
count = 0;
lastCmap = None;
lastWindow = None;
for (xi = 0; xi < width; xi++, count++) {
xyToWindowCmap(dpy, xi + x, yi + y, root, &nx, &ny, &window, &cmap);
if ((window != lastWindow || cmap != lastCmap) && count != 0) {
if (cmap == lastCmap && lastWindow == root)
continue;
xim = XGetImage(dpy, lastWindow, fx, fy, count, 1,
AllPlanes, ZPixmap);
for (i = 0; i < count; i++) {
xcol[i].pixel = XGetPixel(xim, i, 0);
xcol[i].flags = DoRed|DoGreen|DoBlue;
}
XQueryColors(XtDisplay(w), lastCmap, xcol, count);
for (i = 0; i < count; i++) {
*ip++ = (xcol[i].red >> 8) & 0xff;
*ip++ = (xcol[i].green >> 8) & 0xff;
*ip++ = (xcol[i].blue >> 8) & 0xff;
}
XDestroyImage(xim);
count = 0;
}
if (count == 0) {
fx = nx;
fy = ny;
if (cmap == dmap) {
fx = x + xi;
fy = y + yi;
lastWindow = root;
} else {
lastWindow = window;
}
lastCmap = cmap;
}
}
if (count != 0) {
xim = XGetImage(dpy, lastWindow, fx, fy, count, 1,
AllPlanes, ZPixmap);
for (i = 0; i < count; i++) {
xcol[i].pixel = XGetPixel(xim, i, 0);
xcol[i].flags = DoRed|DoGreen|DoBlue;
}
XQueryColors(XtDisplay(w), lastCmap, xcol, count);
for (i = 0; i < count; i++) {
*ip++ = (xcol[i].red >> 8) & 0xff;
*ip++ = (xcol[i].green >> 8) & 0xff;
*ip++ = (xcol[i].blue >> 8) & 0xff;
}
XDestroyImage(xim);
}
}
StateSetBusyWatch(False);
#endif
XtFree((XtPointer)xcol);
XDestroyImage(xim);
return (void*)image;
}
void DoGrabPixel(Widget w, Pixel *p, Colormap *cmap)
{
int x, y, nx, ny;
XImage *xim;
Colormap amap;
Window root = RootWindowOfScreen(XtScreen(w));
Window window;
Display *dpy = XtDisplay(w);
doGrab(w, 0, 0, &x, &y);
if (cmap == NULL)
cmap = &amap;
xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, cmap);
xim = XGetImage(dpy, window, nx, ny, 1, 1, AllPlanes, ZPixmap);
if (p != NULL)
*p = XGetPixel(xim, 0, 0);
XDestroyImage(xim);
}
XColor *DoGrabColor(Widget w)
{
static XColor xcol;
Colormap cmap;
Pixel p;
DoGrabPixel(w, &p, &cmap);
xcol.pixel = p;
xcol.flags = DoRed|DoGreen|DoBlue;
XQueryColor(XtDisplay(w), cmap, &xcol);
return &xcol;
}